/*->c.serialdev */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.os"
#include "h.wimp"
#include "h.bbc"
#include "h.flex"
#include "h.swis"

#include "h.wos"
#include "h.main"
#include "h.ram"
#include "h.mym"
#include "h.pr"
#include "h.fsx"
#include "h.dir"
#include "h.trans"

#include "h.xext"
#include "h.script"
#include "h.serial"

#include "h.serialdev"


/***************************************************************************/

extern int serialdevcalllo(int fn,int r1,int r2,int r3);

static int   deviceactive;
static char  devicename[16];
       int   deviceport;
       int * deviceblock;
static int   deviceflags;


#define DEVNEEDSPOLL 0x10
                   

static void codesync(int * lo,int * hi)
{
 os_regset rx;

 rx.r[0]=1;
 rx.r[1]=(int)lo;
 rx.r[2]=(int)hi;

 os_swix(OS_SynchroniseCodeAreas,&rx);
}



static os_error * loadblock(char * name)
{
 os_error * err;
 char       string[128];
 fstat      fs;

 if(!getenv("SerialDev$Path")) fatalerror("{SDEV00}");

 sprintf(string,"SerialDev:Modules.%s.Driver",name);

 err=stat(string,&fs);
 if(err) report(err);
 else
 if(!fs.object || !fs.length) errorbox("{SDEV01}");
 else
 {
  if(deviceblock)
  {
   free(deviceblock);
   remzeroevent(SDEVZERO);
  }

  deviceblock=malloc(fs.length);
  if(!deviceblock) 
    fatalerror("{SDEV02}");

  err=fs_loadblock(string,deviceblock);
  if(!err)
  {
   deviceflags=deviceblock[0xC4/sizeof(int)];
   if(deviceflags & DEVNEEDSPOLL) addzeroevent(SDEVZERO);
   codesync(deviceblock,deviceblock+(fs.length/4));
  }
  else report(err);
 }
 return(err);
}


/* set device name and port            */
/* setserialdev(string & name,int port */

void setserialdev(int fp)
{
 strcpy(devicename,stringptr(stack[fp]));
 deviceport=stack[fp+1];
 if(deviceactive) loadblock(devicename);
}


void sdevzero(void)
{
 xexec("device_poll",NULL,&deviceport,NULL);
}


/* serialdevinit(int active) */

void serialdevinit(int fp)
{
 deviceactive=stack[fp];
}

/* int serialdevcall(int fn,int r1,int r2,int r3) */
/* return r0 */

int serialdevcall(int fp)
{
 if(deviceblock)
      return(serialdevcalllo(stack[fp],stack[fp+1],stack[fp+2],stack[fp+3]));
 else return(0);
}


int serialdevread(int fp)
{
 int index;
 index=stack[fp];
 if(deviceblock) return(deviceblock[index/sizeof(int)]);
 else            return(0);
}


int serialdevget(int port)
{
 if(deviceblock) return(serialdevcalllo(1,port,0,0));
 else            return(-1);
}


int serialdevput(int byte,int port)
{
 if(deviceblock) return(serialdevcalllo(0,port,byte,0));
 else            return(byte);
}


int sdevblockread(int port,char * data,int n)
{
 if(deviceblock) return(serialdevcalllo(3,port,(int)data,n));
 else            return(0);
}


int sdevblockwrite(int port,char * data,int n)
{
 if(deviceblock) return(serialdevcalllo(2,port,(int)data,n));
 else            return(0);
}


int sdevrates(int targetrate)
{
 int  * fontp;
 int  * fontm;
 int    maxwidth=0;
 int    rate;
 char   temp[32];
 int  * p;
 int    tick;

 if(deviceblock)
 {
  fontm=(int*)myrambuff;

  usedrambuff=1;
  strings=myrambuff+MYRMAX;

  fontp=fontm+7;
  p=deviceblock+(0x100/sizeof(int));
  while(1)
  {
   rate=*p++;
   if(!rate) break;
   sprintf(temp,"%d",rate);

   tick=(targetrate==rate);

   writemitem(&fontp,temp,tick,0,&maxwidth);

   if((strings-(char*)fontp)<0x80) break; /* leave some room for ustyles */
  }

  *(fontp-6)|=0x80;

  writemheader(fontm,transtoken("RATE"),maxwidth); /* Fonts */

  return(1);
 }
 else
 {
  return(0);
 }
}




/* return rate or 0 */

int sdevdecoderate(int m2)
{
 int * p;
 int   rate;

 if(deviceblock)
 {
  p=deviceblock+(0x100/sizeof(int));
  p+=m2;
  rate=*p;

  untickmenu((int*)myrambuff);
  tick((int*)myrambuff,m2);
 }
 else rate=0;

 return(rate);
}

